#include "gen_empty.h" 

#include "message.h"
#include "play_message.h"
#include "interpreter.h"
#include "queue.h"
#include "worker_thread.h"
#include "receiver_thread.h"
#include "error_message.h"

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <sstream>
#include <list>
#include <iostream>
#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>

#include "wa502_sdk/gen_ml/listview.h"
#include "wa502_sdk/gen_ml/childwnd.h"
#include "wa502_sdk/winamp/wa_dlg.h"
#include "wa502_sdk/gen_ml/itemlist.h"

using namespace std;

int init(void); 
int proc(int, int, int, int); 
void quit(void);
void insert(itemRecord &r);

boost::mutex mtx;

list<interpreter*> _data;

boost::shared_ptr<worker_thread> _receiver;
boost::shared_ptr<queue> _queue;
boost::shared_ptr<my_socket> _socket;
boost::shared_ptr<boost::thread> _init_thread;

string _client_name;

winampMediaLibraryPlugin plugin = {
	  MLHDR_VER,
	  "MyEmpyProject vx.x (ml_empty.dll)", // Plug-in description 
	  init,
	  quit, 
	  proc,
}; 

interpreter* find_interpreter(itemRecord &r)
{
	for(list<interpreter*>::const_iterator i = _data.begin(); 
	    i != _data.end(); ++i) {
		if((*i)->get_name() == r.artist) {
			return *i;
		}
	}
	return 0;
}

album* find_album(itemRecord &r, interpreter *inter)
{
	for(list<album*>::const_iterator i = inter->get_albums().begin(); 
	    i != inter->get_albums().end(); ++i) {
		string tmp(r.album);
		if((*i)->get_name() == tmp) {
			return *i;
		}
	}
	return 0;
}

title* find_title(itemRecord &r, album *a)
{
	for(list<title*>::const_iterator i = a->get_titles().begin();
	    i != a->get_titles().end(); ++i) {
		string tmp(r.title);
		if((*i)->get_name() == tmp) {
			return *i;
		}
	}
	return 0;
}

void insert(itemRecord &r)
{
	interpreter *i = find_interpreter(r);
	if(i == 0) {
		i = new interpreter(r.artist);
		_data.push_back(i);
	}

	album *a = find_album(r, i);
	if(a == 0) {
		a = new album(r.album);
		i->get_albums().push_back(a);
	}

	title *t = find_title(r, a);
	if(t == 0) {
		t = new title(r.title, r.filename, r.length);
		a->get_titles().push_back(t);
	}
}

void play(title *t)
{
	boost::mutex::scoped_lock l(mtx);
	cout << "playing file..." << endl;
	char *tmp = new char[t->get_file().size() + 1];
	strncpy(tmp, t->get_file().c_str(), t->get_file().size());
	tmp[t->get_file().size()] = '\0';
	cout << tmp << endl;
	mlQueryStruct q = {tmp, 0, {NULL, 0, 0}};
	cout << "before query" << endl;
	SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM) &q, 
						ML_IPC_DB_RUNQUERY_FILENAME);
	cout << "after query..." << endl;
	if(q.results.Size < 1) {
		cout << "sorry, no results found!" << endl;
		return;
	}

	COPYDATASTRUCT cds;
	cds.dwData = IPC_ENQUEUEFILE;
	cds.lpData = (void*)tmp;
	cds.cbData = lstrlen((char*) cds.lpData) + 1;
	SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE);
	SendMessage(plugin.hwndWinampParent, WM_COPYDATA, 0, (LPARAM) &cds);
	SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY);
/*	
 	itemRecordList rl = {0, 0, 0};
	allocRecordList(&rl, 1, 256);
	rl.Items[0] = q.results.Items[0];
	cout << rl.Size << " " << rl.Alloc << " " << rl.Items[0].Artist << endl;
	mlSendToWinampStruct s = {ML_TYPE_ITEMRECORDLIST, (void*)&rl, 
		false};
	cout << "before sending message..." << endl;
	SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 
		    (WPARAM)&s, ML_IPC_SENDTOWINAMP);
	cout << "message sended..." << endl;
*/
}

void pause()
{
	boost::mutex::scoped_lock l(mtx);
	cout << "pause" << endl;
	SendMessage(plugin.hwndWinampParent, WM_COMMAND, 40046, 0);
}

void CALLBACK doit(HWND hwnd, UINT msg, UINT idTimer, DWORD dwTime)
{
	boost::shared_ptr<message> m(_queue->get());
	if(m.get() == 0) {
		return;
	}

	if(m->type() == message::PAUSE) {
		pause();
	} else if(m->type() == message::PLAY) {
		boost::shared_ptr<play_message> pm(
			boost::dynamic_pointer_cast<play_message>(m));
		play(pm->get_title().get());
		pm->get_title().reset();
		pm.reset();
	} else if(m->type() == message::LIST) {
		send_list();
	} else if(m->type() == message::ERR) {
		boost::shared_ptr<error_message> em(
			boost::dynamic_pointer_cast<error_message>(m));
		MessageBox(NULL, em->what().c_str(), "Error", MB_OK);
	}
	m.reset();
}

void send_list()
{
	boost::mutex::scoped_lock l(mtx);
	string tmp = "<client name=\"" + _client_name + "\">";
	for(list<interpreter*>::iterator i = _data.begin(); 
	    i != _data.end(); ++i ) {
		tmp += (*i)->to_xml();
	}
	tmp += "</client>";
	_socket->write(tmp);
}

void init_socket_priv()
{
	try {
		ifstream ifs("C:\\socket.txt");

		if(!ifs.good()) {
			MessageBox(NULL, "fehler", "test", MB_OK);
		}

		string addr;
		int port;
		ifs >> addr >> port;
		_socket.reset(new my_socket(addr, port));
		_receiver.reset(new receiver_thread(_socket, _queue));
		_receiver->start();
		send_list();
	} catch(const exception &e) {
		_queue->put(boost::shared_ptr<message>(
			new error_message(e.what())));
	}
}

void init_socket()
{
	_queue.reset(new queue());
	_init_thread.reset(new boost::thread(&init_socket_priv));
}

int init() 
{
	ifstream ifs("C:\\client.txt");
	ifs >> _client_name;
	ifs.close();
	mlQueryStruct q = {"", 0, {NULL, 0, 0}};
	SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM) &q, 
						ML_IPC_DB_RUNQUERY);
	for(int i = 0; i < q.results.Size; ++i) {
		insert(q.results.Items[i]);
	}
	/*string tmp;
	for(list<interpreter*>::iterator i = _data.begin(); 
	    i != _data.end(); ++i ) {
		tmp += (*i)->to_xml();
	}

	play(_data.front()->get_albums().front()->get_titles().front());
	pause();
	*/
	try {
		init_socket();
		SetTimer(plugin.hwndWinampParent, 12182, 10, (TIMERPROC)&doit);
	} catch (exception &e) {
		MessageBox(NULL, e.what(), "Error", MB_OK);
	}
	return 0; 
} 

void quit() 
{ 
	KillTimer(plugin.hwndWinampParent, 12182);
	for(list<interpreter*>::iterator i = _data.begin(); 
	    i != _data.end(); ++i) {
		delete (*i);
	}
} 

int proc(int message_type, int param1, int param2, int param3)
{
	return 0;
}

extern "C" {
	__declspec(dllexport) winampMediaLibraryPlugin* 
		winampGetMediaLibraryPlugin() {
		  return &plugin; 
	}
}

